
#pragma once
#include <iterator>
template<class T>
struct node
{
	T value;
	node<T> *next;

	node()
	{
		next = nullptr;
	}

	node(const T &t)
	{
		value = t;
		next = nullptr;
	}
};

template<class T>
class forward_list
{
private:
	node<T> *head;
public:

	forward_list()
	{
		head = nullptr;
	}
	forward_list(forward_list& fli)
	{
		head = nullptr;
		if (!fli.is_empty())
		{
			int i = 0;
			iterator it_b = fli.begin();
			iterator it_e = fli.end();
			push_front(it_b->value);
			it_b++;
			while (it_b != it_e)
			{
				insertAfter(it_b->value, i);
				it_b++;
				i++;
			}
		}
	}
	forward_list &operator=(forward_list &fli)
	{
		this->clear();
		if (!fli.is_empty())
		{
			int i = 0;
			iterator it_b = fli.begin();
			iterator it_e = fli.end();
			push_front(it_b->value);
			it_b++;
			while (it_b != it_e)
			{
				insertAfter(it_b->value, i);
				it_b++;
				i++;
			}
		}
	}

	bool is_empty() { return head == nullptr; }

	void push_front(const T& value)
	{
		node <T> *n = new node <T>(value);
		n->next = head;
		head = n;
	}

	void pop_front()
	{
		if (head != nullptr)
		{
			node <T> *tempNode;
			tempNode = head;
			head = tempNode->next;
			delete tempNode;
		}
	}

	void clear()
	{
		while (head != nullptr)
		{
			pop_front();
		}
	}

	T front()
	{
		return head->value;
	}

	void iteratorBegin()
	{
		iterator it = begin();
	}

	void iteratorEnd()
	{
		iterator it = end();
	}

	int forwardListSize()
	{
		node <T> *n = head;
		int count = 0;
		while (n != nullptr)
		{
			n = n->next;
			count++;
		}
		return count;
	}

	void insertAfter(const T&value, int index)
	{
		iterator it = begin();
		node <T> *n = new node <T>(value);
		for (size_t i = 0; i < index; i++)
		{
			it++;
		}
		if (it != nullptr)
		{
			n->next = it->next;
			it->next = n;
		}
	}

	void eraseAfter(int index)
	{
		iterator it = begin();
		for (int i = 0; i < index - 1; i++)
		{
			it++;
		}
		node<T> *nodeAfterDeleted = it->next->next;
		node<T> *nodeToDelete = it->next;
		delete nodeToDelete;
		it->next = nodeAfterDeleted;
	}

	void swap(forward_list<T> &fli)
	{
		node <T> *temp = head;
		head = fli.head;
		fli.head = temp;
	}

	~forward_list()
	{

	}
	class iterator
	{
	public:
		typedef iterator self_type;
		typedef node<T>  value_type;
		typedef node<T>& reference;
		typedef node<T>* pointer;
		typedef std::forward_iterator_tag iterator_category;
		typedef int difference_type;

		iterator(pointer ptr) : ptr_(ptr) { } //Constructor
		self_type operator++()
		{
			self_type i = *this;
			ptr_ = ptr_->next;
			return i;
		}
		self_type operator++(int junk) { ptr_ = ptr_->next; return *this; }
		reference operator*() { return *ptr_; }
		pointer operator->() { return ptr_; }
		bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
		bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }

	private:
		pointer ptr_;
	};

	iterator begin() { return iterator(head); }
	iterator end() { return iterator(nullptr); }
};